import os.path
import platform
import re
import time
import unittest

import allure
import pyautogui
import pywinauto
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
import psutil

from appium import webdriver

from bin.LoggerBase import log
from CaseAW import classtype_map
from openpyxl.drawing.image import Image as excelImage

from CaseAW.imgAssert import assert_img_gray


class winAppBase(unittest.TestCase):
    def __init__(self,desired_caps=None,host="localhost",port="4723"):
        if self.get_system_version()=="7":
            port="9999"
            desired_caps={"platformName":"Windows","app":"D:/empty.bat","autoLauch":0}
        elif desired_caps==None:
            desired_caps={"platformName":"Windows","app":"Root","autoLauch":"false"}
        self.driver=webdriver.Remote("http://{}:{}".format(host,port),desired_caps)
        log.info("service start")
        self.log=log
        self._type_equality_funcs={}

    def get_system_version(self):
        """
        获取windows系统版本
        """
        return platform.release()

    def find_element_by_xpath(self,xpath,classIndex=0):
        """
        win7的元素定位
        """
        def analysis_path(xpath) :
            search_path=[]
            string_list=xpath.split("/")
            namelist=[x for x in string_list if "" != x]
            for index,name in enumerate(namelist):
                if "@Name" in name :
                    groups=re.search(r"/(\w+)\[@Name='(.+)'\]",xpath).groups()
                    assert groups[0] in classtype_map.keys(),groups[0]
                    root_class=classtype_map[groups[0]]
                    search_path.append({"classname":root_class,"name":groups[1]})
                    break
            if "@Name" not in namelist[-1]:
                lastrank={}
                if "[" in namelist[-1]:
                    index =int(re.search("\d",namelist[-1]).group())-1
                    target=namelist[-1][:-3]
                    lastrank.update({"index":index})
                else:
                    target=namelist[-1]
                assert target in classtype_map.keys(),target
                if isinstance(classtype_map[target],list):
                    target_calss=classtype_map[target][classIndex]
                else:
                    target_calss=classtype_map[target]
                lastrank.update({"classname":target_calss})
                search_path.append(lastrank)
            return search_path

        if self.get_system_version()=="10":
            return self.driver.find_element_by_xpath(xpath)
        elif self.get_system_version()=="7":
            ranklist=analysis_path(xpath)
            return self.find_element_by_rank(ranklist)

    def get_element_rectangle(self,element):
        """
        通过属性标签，获取面板坐标值
        """
        val=element.get_attribute("BoundingRectangle")
        if self.get_system_version()=="7":
            rect=tuple(val.split(","))
        else:
            Left=str(re.findall("Left:(.*) Top:",val)[0])
            Top=str(re.findall("Top:(.*) Width:",val)[0])
            Width=str(re.findall("Width:(.*) Height:",val)[0])
            Height=str(re.findall("Height:(.*)",val)[0])
            rect=(Left,Top,Width,Height)
        return rect

    def picture_shot(self,me,place,picture_path,offset=(7,5,-14,-12)):
        """
        自定义截图
        me:定位方法
        place:元素名称
        picture_path:图片保存路径
        picture_path：图片截取范围
        """
        if me=="classname":
            ele=self.driver.find_element_by_class_name(place)
        elif me=="name":
            ele=self.driver.find_element_by_name(place)
        elif me=="xpath":
            ele=self.driver.find_element_by_xpath(place)
        elif me=="uid":
            ele=self.driver.find_elemet_by_accessibility_id(place)
        else:
            raise Exception("请输入正确的元素定位方法！！！")
        val=ele.get_attribute("BoundingRectangle")
        if self.get_system_version()=="7":
            ltrb=val.split(",")
            l=ltrb[0]
            t=ltrb[1]
            r=ltrb[2]
            b=ltrb[3]
            Left1=int(l)+offset[0]
            Top1=int(t)+offset[1]
            Width1=int(r)+offset[2]
            Height1=int(b)+offset[3]
            a=(Left1,Top1,Width1,Height1)
            expect_picture=pywinauto.screenshot(region=(a))
            expect_picture.save(picture_path)
            log.info("名称为{}的面板截图成功。。。".format(place))
        elif self.get_system_version()=="10":
            Left=str(re.findall("Left:(.*) Top:",val)[0])
            Top=str(re.findall("Top:(.*) Width:",val)[0])
            Width=str(re.findall("Width:(.*) Height:",val)[0])
            Height=str(re.findall("Height:(.*)",val)[0])
            Left1 = int(Left) + offset[0]
            Top1 = int(Top) + offset[1]
            Width1 = int(Width) + offset[2]
            Height1 = int(Height) + offset[3]
            a=(Left1,Top1,Width1,Height1)
            expect_picture=pywinauto.screenshot(region=(a))
            expect_picture.save(picture_path)
            log.info("名称为{}的面板截图成功。。。".format(place))

    def picture_assert2(self,expect_pic,fact_pic,threshold:int):
        """
        图片断言
        """
        score,diff_img_path=assert_img_gray(img_fact=fact_pic,img_expected=expect_pic)
        def report(score,threshold):
            with open(expect_pic,mode="rb") as f1,open(fact_pic,mode="rb") as f2,open(diff_img_path,mode="rb") as f3:
                string001="图片不一致！！要求{}，实际值{}".format(threshold,score)
                log.info(string001)
                with allure.step(string001):
                    allure.attach(f1.read(),"expect_pic",allure.attachment_type.PNG)
                    allure.attach(f2.read(), "fact_pic", allure.attachment_type.PNG)
                    allure.attach(f3.read(), "diff_img_path", allure.attachment_type.PNG)
                return string001
        if self.get_system_version()=="7":
            threshold=threshold-8
        assert score > threshold,report(score, threshold)

    def check(self,key_word,interval=30,times=20):
        """
        轮询函数指定循环次数和查找时间，查找关键字
        """
        def demo():
            try:
                result=self.get_text_table()
            except:
                log.info("查找关键词失败。。。")
                return False
            if key_word in result:
                log.info("已查找到关键词！")
                return True
            else:
                log.info("正在查找关键词。。。")
                return False
        self.loop_check(call_method=demo,interval=interval,times=times)

    def loop_check(selfself,call_method,interval=30,times=20):
        """
        循环函数：指定函数，查找关键字
        """
        for i in range(times):
            result=call_method()
            if result:
                break
            time.sleep(interval)
        else:
            raise Exception("超过时间，未查找到结果")

    def generate_pic_path(self,file):
        """
        返回file的所在路径
        """
        cwdpath=os.path.abspath(file)
        basename=os.path.basename(file)
        cwdpath=cwdpath.replace(basename,"")
        return cwdpath

    def run_window_check(self,windowsname="正在生成网格......",timeout=600):
        """
        检查计算生成的弹窗是否存在
        """
        runtime=0
        while runtime<=timeout:
            time.sleep(20)
            try:
                self.driver.find_element_by_name(windowsname)
            except:
                break
            else:
                log.info("生成中...等待下次查询")
                runtime+=20
                continue
        else:
            raise Exception("检查生成网格超时！ 已经耗时%d分钟"%(timeout/60))

    def snap_shot(self,text,stepname="snapshot"):
        """
        allure报告获取图片结果
        """
        with allure.step(stepname):
            allure.attach(self.driver.get_screenshot_as_png(),"snap_shot_png",allure.attachment_type.PNG)
            allure.attach(text,stepname,allure.attachment_type.TEXT)

    def text_step(self,text,stepname="text"):
        """
        allure报告获取结果
        """
        with allure.step(stepname):
            allure.attach(text,stepname,allure.attachment_type.TEXT)

    def attach_step(self,text=None,pngname=None):
        """
        allure报告获取文字结果和图片结果
        """
        if text==None:
            if pngname==None:
                pngname="snap_shot_png"
            allure.attach(self.driver.get_screenshot_as_png(),pngname,allure.attachment_type.PNG)
        else:
            allure.attach(text,"文字信息",allure.attachment_type.TEXT)

    def send_data(self,xpath,data,classtype=0):
        """
        输入框输入数值
        """
        element=self.find_element_by_xpath(xpath,classIndex=classtype)
        self.clear_text(element)
        element.send_keys(data)

    def assert_checkbox(self,ele):
        """
        判断是否勾选复选框
        """
        return ele.is_selected()

    def attach_caseinfo(self,infodict=None):
        """
        allure报告获取禅道用例信息
        """
        if infodict!=None and "id" in infodict.keys():
            title=infodict["title"]
            caseid=infodict["caseid"]
            story="--".join([str(caseid),title])
            allure.dynamic.feature(story)
            allure.dynamic.story(story)
            allure.dynamic.title(story)
            info="前置条件\n"+infodict["precondition"]+"\n 步骤与预期：\n"
            for index,i in enumerate(infodict["steps"]):
                h1=str(index+1) +"."+i["desc"]+"----->"+i["expect"]+"\n"
                info+=h1
            allure.dynamic.description(info)
            level=str(infodict["pri"])
            allure.dynamic.tag(level)

    def right_click_element(self,element):
        """
        鼠标右键点击元素
        """
        rect=self.get_element_rectangle(element)
        x=int(rect[0])+int(rect[2])/2
        y=int(rect[1])+int(rect[3])/2
        pyautogui.click(x=x,y=y,button="RIGHT")

    def get_combobox_value(self,ele,min,max,x1=0,y1=0,x2=0,y2=0,duration=1):
        """
        获取下拉列表内容，超过一定数值范围需要显示以后再获取
        """
        ComboBox=self.find_element_by_xpath(ele)
        ComboBox.click()
        self.change_panel_size(x1,y1,x2,y2,duration)
        ListItem=[]
        for i in range(min,max):
            items=self.find_element_by_xpath("//List"%i)
            items_name=items.get_attribute("Name")
            ListItem.append(items_name)
        return ListItem

    def assert_ele_expect_value(self,ele,expectValue):
        """
        断言
        """
        assert ele.text==expectValue,"内容与预期不符：%s"%ele.text

    def assert_window_exist(self,name):
        """
        判断弹窗是否存在
        """
        try:
            self.find_element_by_xpath("//Window[@Name='%s']"%name)
        except:
            return False
        return True

    def comparsion_time(self,button,key_word,interval=60,times=60,expect_time=20):
        """
        指定功能的响应时间性能指标对比
        """
        start_time=time.time()
        self.driver.find_element_by_name(button).click()
        self.check(key_word,interval=interval,times=times)
        end_time=time.time()
        execution_time=end_time-start_time
        if execution_time<=expect_time:
            print("响应时间达标，预期为{:.2f}s,实际为：{:.2f}s".format(expect_time,execution_time))
        else:
            raise Exception("响应时间不达标！！预期为{:.2f}s,实际为：{:.2f}s".format(expect_time,execution_time))

    def comparsion_cpu_memory(self, button, key_word, interval=60, times=60, expect_cpu_usage=40,
                              expect_memory_usage=20):
        """
        指定功能的内存及CPU性能指标对比
        """
        self.driver.find_element_by_name(button).click()
        self.check(key_word, interval=interval, times=times)
        cpu_usage=psutil.cpu_percent(interval=1)
        memory_usage=psutil.virtual_memory().percent
        if cpu_usage <= expect_cpu_usage:
            print("CPU达标，预期为{:.2f}s,实际为：{:.2f}s".format(cpu_usage,expect_cpu_usage))
        else:
            raise Exception("CPU不达标！！预期为{:.2f}s,实际为：{:.2f}s".format(cpu_usage,expect_cpu_usage))
        if memory_usage <= expect_memory_usage:
            print("内存达标，预期为{:.2f}s,实际为：{:.2f}s".format(memory_usage,expect_memory_usage))
        else:
            raise Exception("内存不达标！！预期为{:.2f}s,实际为：{:.2f}s".format(memory_usage,expect_memory_usage))

    def find_element_by_rank(self,rank_list,f_ele=None):
        """
        通过传入搜索序列，进行元素定位
        每循环一次返回一个下层元素，在下层元素的基础上继续查找
        """
        if f_ele==None:
            if self.get_system_version()=="7":
                c_element=self.driver.find_element_by_class_name("WindowForm")
            else:
                c_element=self.driver.find_element_by_accessibility_id("Dcax_Grid_MainWindow")
        else:
            c_element=f_ele

        for s_dict in rank_list:
            c_element=self.__find_element_by_rank_sub(s_dict,f_element=c_element)
        return c_element

    def __find_element_by_rank_sub(self,s_dict,f_element=None):
        """
        {"classname":"","name":"","index":0}
        无index,则默认第一个
        """
        ss_element=[]
        if f_element==None:
            f_element=self.driver
        if self.get_system_version()=="7" and "name" in s_dict.keys() and s_dict["name"]==None:
            s_dict.update({"name":""})
        if "classname" in s_dict.keys():
            list1=f_element.find_element_by_class_name(s_dict["classname"])
            if "name" in s_dict:
                for ele in list1:
                    if ele in list1:
                        if ele.get_attribute("Name")==s_dict["name"]:
                            ss_element.append(ele)
            else:
                ss_element=list1
        else:
            ss_element=f_element.find_element_by_name(s_dict["name"])
        assert len(ss_element)!=0,s_dict
        if "index" in s_dict:
            return ss_element[s_dict["index"]]
        else:
            return ss_element[0]





























































